﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.ServiceModel;
using FinPlusCommon;
using FinPlusComponents;
using System.Reflection;
using System.Collections.Concurrent;
using System.Threading;
using u = FinPlusUtility.Utility;
using log = Logger.Logger;

namespace FinPlusWCFService
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
    public class FinPlusServices : IFunctionService
    {
        private static ConcurrentDictionary<string, FinPlusService> _services = new ConcurrentDictionary<string, FinPlusService>();
        private string _targetAssemblys, _configFolder;
        private int _asyncWait, _asyncRetry;
        private bool _hasInitialised;
        private u.Env _env;

        //public
        public void GetFunctions(u.Env env, string user, string config, string serviceName, string serviceType, string parms, string guid)
        {
            try
            {
                if (!_hasInitialised) Initialise();

                FinPlusService service;
                if (!_services.ContainsKey(serviceName))
                {
                    lock (_services)
                    {
                        if (!_services.ContainsKey(serviceName))
                            _services.TryAdd(serviceName, service = new FinPlusService(env, serviceName, serviceType, parms, guid, _targetAssemblys, _configFolder, _asyncWait, _asyncRetry));
                    }
                }
     
                _services.TryGetValue(serviceName, out service);
      
                if (!service.HasStarted) 
                    service.Start();
                else
                    service.WaitCompleted();

                service.SendResults(guid);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, e.Message, e);
                throw new FaultException(e.Message);
            }
        }

        public void SaveFunction(u.Env env, string user, string config, string serviceName, IEnumerable<Item> func, ChangeType changeType, string guid)
        {
            try
            {
                FinPlusService service;
                if(_services.TryGetValue(serviceName, out service))
                    service.Component.Model.Update(new Function(func), changeType);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, e.Message, e);
                throw new FaultException(e.Message);
            }
        }

        public void AlterFunction(u.Env env, string user, string config, string serviceName, DateTime timeStamp, string functionName, int id, string itemName, object value)
        {
            try
            {
                FinPlusService service;
                if (!_services.TryGetValue(serviceName, out service)) return;

                if (!service.Component.Model.ContainsKey(id)) return;

                var item = service.Component.Model[id].Get(itemName);
                if (item != null && timeStamp > item.TimeStamp)
                    item.Set(value, timeStamp, user);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, e.Message, e);
                throw new FaultException(e.Message);
            }
        }

        public void Dispose(u.Env env, string user, string config, string serviceName, string guid)
        {
            try
            {
                FinPlusService service;
                if (_services.TryGetValue(serviceName, out service))
                    service.Dispose(guid);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, e.Message, e);
            }
        }

        //private
        private void Initialise()
        {
            var p = u.GetConfigPath(Assembly.GetExecutingAssembly());
            var configs = u.ConfigXml(p, out _env)["configs"];
            log.Initialise(p, _env.ToString());

            _configFolder = configs["configfolder"];
            _targetAssemblys = configs["targetassemblys"];
            _asyncWait = (int)(double.Parse(configs["asyncwait"]) * 1000);
            _asyncRetry = int.Parse(configs["asyncretry"]);
            _hasInitialised = true;
        }
    }
}
